/*
 * trans.h
 *
 *  Created on: 2011-8-16
 *      Author: Baron Wang
 */

#ifndef TRANS_H_
#define TRANS_H_

/*
 * The libtrans is an light-weighted, high performance, event driven socket
 * library which supports:
 *
 *     1,    Trans worker thread model and thread pool.
 *     2,    UDP and TCP event register and notification.
 *     2,    Support both IPv4 and IPv6.
 *     3,    Event timer.
 *
 *     Feature List:
 *    1,    Block send queue. (HIGH)
 *         When sent is EWOULDBLOCK, don't return error and queue it and try to
 *         flush as much as possible when socket is ready. This can largely
 *         improve trans performance.
 *
 *    2,    SCTP support. (HIGH)
 *         Need to add the SCTP support for both base SCTP and multi-homing (using
 *         alternative local and remote).
 *
 *     3,    Bulk socket read. (MEDIUM)
 *         Can read a bulk of data, and then notify user by event.
 *         This can improve user level applicaiton's performance when receving
 *         large data without MTU detection.
 *
 *    4,    IKEv2 or TLS/DTLS support. (LOW)
 *        Software decode consumes lots of CPU, some of it is still needed
 *
 *    5,    T/TCP and Lagecy protocol support, such as TPKT.(LOW)
 *        For T/TCP still need to study. and for TPKT, just provides a way of
 *        binary stream connect.
 */

#include <ev.h>

#include "tsock.h"
#include "tlog.h"

#ifdef __cplusplus
extern "C" {
#endif

#define TIMER_TYPE_UNSET        0
#define TIMER_TYPE_SIMPLE       1
#define TIMER_TYPE_REPEAT       2
#define TIMER_TYPE_INTERNAL     0xBBCD        /* For internal use ONLY */

#define TRANS_SUECCESS          0
#define TRANS_FAILED            -3000
#define TRANS_ALREADY_INITED    -3001
#define TRANS_NOT_INITIALIZE    -3002
#define TRANS_NOT_ENOUGH_MEM    -3003
#define TRANS_INVALID_VALUE     -3004
#define TRANS_A_NULL_POINTER    -3005
#define TRANS_UNSUPPORTED       -3007
#define TRANS_CROSSCHK_FAIL     -3008
#define TRANS_EXCEED_LIMITS     -3019
#define TRANS_NOT_FOUND         -3010
#define TRANS_LIBEV_ERROR       -3011
#define TRANS_TIME_OUT          -3012
#define TRANS_INVALID_TYPE      -4000
#define TRANS_ERROR_MAX         TRANS_INVALID_TYPE

/* This is a common macro to extension the standard errno. */
#define ERROR_TO_STR(_errno)        \
    _errno > TRANS_FAILED ? strerror(errno) : trans_strerror(_errno)

/* The recv buffer size is the internal buffer size append to each socket */
#define RECV_BUFFER_SIZE        (32 * 1024L)
/* SOCKET_BUF_SIZE is the minimum SO_RCVBUF and SO_SNDBUF set by default */
#define SOCKET_BUF_SIZE         (128 * 1024L)

/* Need these opts to simplify the interfaces */
#define SOCK_OPT_BORADCAST      0x00000001
/* IP_ADD_MEMBERSHGIP / IPV6_JOIN_GROUP and DROP and LEAVE */
#define SOCK_OPT_MCAST_ADD      0x00000002
#define SOCK_OPT_MCAST_RMV      0x00000004
/* IP_MULTICAST_LOOP and IPV6_MULTICAST_LOOP */
#define SOCK_OPT_MCAST_LOP      0x00000008

#define SOCK_OPT_RCVBUF         0x00000010
#define SOCK_OPT_SEDBUF         0x00000020
#define SOCK_OPT_DEBUG          0x00000040
#define SOCK_OPT_TOS            0x00000080
#define SOCK_OPT_REUSE_ADDR     0x00000100
/* TCP_NODELAY / SCTP_NODELEY */
#define SOCK_OPT_NDLAY          0x00000200
#define SOCK_OPT_LINGER         0x00000400
#define SOCK_OPT_CLOSE_ERR      0x00000800
#define SOCK_OPT_LISTEN_ONCE    0x00001000
#define SOCK_OPT_LOCAL_PORT     0x00002000
#define SOCK_OPT_SCTP_ALTER     0x00004000
#define SOCK_OPT_NON_BLOCKING   0x00008000

#define SOCK_OPT_MINIMAL                        \
        (SOCK_OPT_NDLAY |                       \
         SOCK_OPT_NON_BLOCKING)

/* Use the default value if you don't know how to use it */
#define SOCK_OPT_DEFAULT                        \
        (SOCK_OPT_RCVBUF |                      \
         SOCK_OPT_SEDBUF |                      \
         SOCK_OPT_NDLAY  |                      \
         SOCK_OPT_NON_BLOCKING)

/* If you want a restict socket for error(on_sock_err), try this */
#define SOCK_OPT_DEFAULT_RESTRICT               \
        (SOCK_OPT_RCVBUF |                      \
         SOCK_OPT_SEDBUF |                      \
         SOCK_OPT_NDLAY |                       \
         SOCK_OPT_NON_BLOCKING |                \
         SOCK_OPT_CLOSE_ERR)

/*
 +--------------------------+---------------------+---------------------+
 |                          |        IPv4         |        IPv6         |
 +        flag              +---------------------+---------------------+
 |                          |  UDP   TCP   SCTP   |  UDP   TCP   SCTP   |
 |--------------------------+---------------------|---------------------|
 | SOCK_OPT_BORADCAST       |   *                 |                     |
 | SOCK_OPT_MCAST_ADD (1)   |   *            *    |   *            *    |
 | SOCK_OPT_MCAST_RMV       |   *            *    |   *            *    |
 | SOCK_OPT_MCAST_LOP       |   *            *    |   *            *    |
 | SOCK_OPT_RCVBUF          |         *      *    |          *     *    |
 | SOCK_OPT_SEDBUF          |   *     *      *    |   *      *     *    |
 | SOCK_OPT_DEBUG           |   -     -      -    |   -      -     -    |
 | SOCK_OPT_TOS             |   -     -      -    |   -      -     -    |
 | SOCK_OPT_NDLAY     (2)   |         A      A    |          A     A    |
 | SOCK_OPT_LINGER          |         *      *    |          *     *    |
 | SOCK_OPT_CLOSE_ERR       |   *     *      *    |   *      *     *    |
 | SOCK_OPT_LISTEN_ONCE     |   *     *      *    |   *      *     *    |
 | SOCK_OPT_LOCAL_PORT      |   *     *      *    |   *      *     *    |
 | SOCK_OPT_SCTP_ALTER      |                *    |                *    |
 | SOCK_OPT_NON_BLOCKING (3)|   *     *      *    |   *      *     *    |
 +--------------------------+---------------------+---------------------+
 *
 *        (1) for multicast add, both IPv4 and IPv6 is supported, but for IPv4
 *            the local IP address can be bind (of course user can choose the
 *            loop back), but for IPv6, system will choose an any address to send
 *            and recv currently.
 *
 *            which means, if SOCK_OPT_MCAST_ADD for IPv4, user can set
 *            SOCK_OPT_MCAST_LOP
 *
 *            if SOCK_OPT_MCAST_ADD for IPv6, it will not work.
 *
 *            All judgement depends on remote address not local.
 *
 *        (2) for SOCK_OPT_NDLAY, it is automatically set when using because we
 *            need non-blocking IO.
 *
 *        (3) for SOCK_OPT_NON_BLOCKING, it is strongly recommand using. Set by
 *            default.
 *
 */

typedef struct{
    pthread_attr_t      *t_attr;            /* thread attributes            */
    int                 num_of_worker;      /* thread number                */
    int                 max_socket_num;     /* socket slots per thread      */
    log_opt             *l_opt;             /* logger opt could be NULL if
                                                _NO_LOG or _USE_SYSLOG      */
}trans_opt;


typedef int (*timer_cb)(int id, void *tlc, void *ulc);  /* timer callback   */

/* Result code for the on_new function, user should only return one of this */
#define    APP_ACCEPT      0
#define    APP_IGNORE      -1
#define    APP_REJECT      -2

typedef struct{

    /* on_connect is called when the client is accept by remote */
    int (*on_connect)(void *llc, void *ulc);

    /* on_new callback should be used by server
     * return APP_ACCEPT, APP_IGNORE(n/a) or APP_REJECT
     * and the return value is a MUST for server to continue
     */
    int (*on_new)(void *llc, void *ulc, void **out_ulc, tsock_ep *ep);

    /* callback when recv packages */
    int (*on_read_tcp)(void *llc, void* ulc, char* buf, int len);
    int (*on_read_udp)(void *llc, void* ulc, tsock_ep *from,
        tsock_ep *to, char* buf, int len);

    /* callback of when close and receive sctp events (subscribed) */
    int (*on_close)(void *llc, void *ulc, int err);
    int (*on_sctp_event)(void *llc, void *ulc, int event, char* buf, int len);

    /* the error call back, use ERROR_TO_STR(err) to get the reason */
    int (*on_sock_err)(void *llc, void *ulc, int err);
    int (*on_listen_err)(void *llc, void *ulc, int err);
    int (*on_conn_err)(void *llc, void *ulc, int err);

    /* to give a default timer call back, can be NULL */
    timer_cb on_default_timer;

}sock_cb;

typedef struct{
    uint        max_input_streams;
    uint        num_output_streams;
    ushort      sctp_profile_id;
    ushort      rto_min;
    uint        rto_max;
    uint        rto_initial;
    ushort      rto_alpha;
    ushort      rto_beta;
    ushort      valid_cookie_life;
    uint        hb_interval;
    ushort      sack_period;
    ushort      sack_frequency;
    uint        mtu_size;
    ushort      bundling_interval;
    ushort      no_delay;
    ushort      assoc_max_retrans;
    ushort      path_max_retrans;
    ushort      max_init_retrans;
    /* this two member it to save the internal data */
    tsock_ep    laddr2;       /* 2ed local address for multi-homed SCTP     */
    tsock_ep    raddr2;       /* 2ed remote address for multi-homed SCTP    */
} sctp_opts;


typedef struct{
    int         opts;         /* the SOCK_OPT_XX attributes                 */
    int         ip_tos;       /* for IP_TOS                                 */
    int         sbuf_size;    /* SO_SNDBUF, no effect if < SOCKET_BUF_SIZE  */
    int         rbuf_size;    /* SO_RCVBUF, no effect if < SOCKET_BUF_SIZE  */
    int         linger_time;  /* SO_LINGER, 0 is infinate                   */
}sock_opts;

/*
 * Description:
 *         trans_strerror : Translate the transerror to string.
 *
 * Parameters:
 *         error_code    - The TRANS_XX code
 *
 * Returns:
 *         The string reason about this error.
 */
const char* trans_strerror(IN int error_code);

/*
 * Description:
 *         trans_version :  Get the version about libtrans.
 *
 * Note:
 *         This function can be overwritten by applications.
 *
 * Returns:
 *         The string indicate the libtrans info.
 */
extern char* trans_version(void);

/*
 * Description:
 *         trans_init : This initiliaze the trans thread.
 *
 * Note:
 *         1, It will be and should be inited ONCE!
 *         2, It MUST be guarded by global mutex when use.
 *         3, Strongly recommand a "quiet time" for listen socket.
 *
 * Parameters:
 *         opt        - The libtrans init parameter
 */
int trans_init(IN trans_opt opt);


/*
 * Description:
 *         trans_fini : This is the finalizer of the trans thread, all resource
 *         will be released and thread dies.
 *
 * Note:
 *         it is supposed that this API will NEVER be called.
 */
void trans_fini(void);

/*
 * Description:
 *         trans_listen : The function of the non-blocking listen.
 *
 *         trans_listen is the entry of the server functionality, so, passing the
 *         callback function list to init all the function.
 *
 * NOTE:
 *         1, the opts we pass, some of the invalid opts will be dropped silently
 *            (or with log).
 *         2, the llc can be NULL, it means no attach socket and let libtrans to
 *            do the load-balance.
 *         3, thread safe.
 *
 * Parameters:
 *        llc         - Attached socket pointer, if NULL, means that there's no
 *                    attachthread, so, the o_llc, will bring the pointer to
 *                    socket pointer out.
 *
 *        ulc         - User-level-context passed in, and it will show up when call
 *                    back is called. libtrans considers it transparent.
 *
 *        o_llc     - Attached llc info passing out, user should keep this as an
 *                    "ID" or "handle" to do other operations.
 *
 *        ep         - Pointer of listen address (or array, if SCTP alternative
 *                    local address, MUST set SOCK_OPT_SCTP_ALTER opt to enable).
 *
 *        cb         - Callback function of the socket, some of them will be
 *                    ignored if no use.
 *
 *        opts     - The SOCK_OPT_ series, suggest to use the default value
 *                    SOCK_OPT_DEFAULT or SOCK_OPT_DEFAULT_RESTRICT.
 *
 *        sopts     - Pointer to SCTP options, if ep is a SCTP, this can NOT be
 *                    empty(NULL), if TCP/UDP, it is NULL or ignored.
 *
 * Return:
 *         The status code, TRANS_SUCCESS will be provided if OK.
 */
int trans_listen(IN void *llc, IN void *ulc, OUT void **o_llc,
    IN tsock_ep *ep, IN sock_cb *cb, IN sock_opts *opts,
    IN sctp_opts *sopts);

/*
 * Description:
 *         trans_connect : The function of the non-blocking connect.
 *
 *        For UDP, it is also need this "connect" because it will register the
 *        socket in the libtrans thread pool, and give user the notification.
 *
 *         trans_listen is the entry of the client functionality, so, passing the
 *         callback function list to init all the function.
 *
 * NOTE:
 *         1, the opts we pass, some of the invalid opts will be dropped silently
 *         2, the llc can be NULL, it means no attach socket and let libtrans to
 *             do the load-balance.
 *
 * Parameters:
 *        llc         - Attached socket pointer, if NULL, means that there's no
 *                    attach infomation, so, the o_llc, will bring the pointer to
 *                    socket pointer out.
 *
 *        ulc         - User-level-context passed in, and it will show up when call
 *                    back is called. libtrans considers it transparent.
 *
 *        o_llc     - Attached llc info passing out, user should keep this as an
 *                    "handle" to do other operations.
 *
 *        l_ep     - Pointer of local address (or array, if SCTP alternative
 *                    local address, MUST set SOCK_OPT_SCTP_ALTER opt to enable).
 *
 *        r_ep     - Pointer of remote address (or array, if SCTP alternative
 *                    local address, MUST set SOCK_OPT_SCTP_ALTER opt to enable).
 *
 *        cb         - Callback function of the socket, some of them will be
 *                    ignored if no use.
 *
 *        opts     - The SOCK_OPT_ series, suggest to use the default value
 *                    SOCK_OPT_DEFAULT or SOCK_OPT_DEFAULT_RESTRICT.
 *
 *        sopts     - Pointer to SCTP options, if ep is a SCTP, this can NOT be
 *                    empty(NULL).
 *
 *        timeout     - Itervel of the timeout in ms, if 0 will return immediately.
 *
 * Return:
 *         The status code, TRANS_SUCCESS will be provided if OK.
 */
int trans_connect(IN void *llc, IN void *ulc, OUT void **o_llc,
    IN tsock_ep *l_ep, IN tsock_ep *r_ep, IN sock_cb *cb,
    IN sock_opts *opts, IN sctp_opts *sopts, IN int timeout);

/*
 * Description:
 *         trans_send : The function of send for either TCP or UDP.
 *
 *        For TCP, becasue the remote is certain, no need to pass remote endpoint
 *        while for UDP if connect() is called, ditto.
 *
 *        It is strongly recommanded that UDP use the last parameter (remote) to
 *        send the diagram to indicated address.
 *
 * NOTE:
 *         1, the last "remote" should be NULL when sending the TCP stream.
 *         2, if the remote is not NULL, the endpoint MUST be a SYS_UDP endpoint,
 *             and trans_send will send an UDP diagram.
 *
 * Parameters:
 *        llc         - Attached socket pointer, should be reserved in trans_listen
 *                    or trans_connect is called (o_llc).
 *
 *        msg         - Message buffer to be send
 *
 *        len         - The lenth of the Message buffer
 *
 *        remote     - Indicated remote endpoint to be sent, if NULL, message will
 *                    be send to the default remote peer user once specified.
 *                    However, if it is not NULL, should be SYS_UDP and a diagram
 *                    will be sent.
 *
 * Return:
 *         The status code, TRANS_SUCCESS will be provided if OK.
 */
int trans_send(IN void *llc, IN char* msg, IN int len, IN tsock_ep* remote);

/*
 * Description:
 *         trans_close : The operation to de-register the socket in libtrans, and
 *         close socket.
 *
 * Parameters:
 *         llc        - Attached socket pointer as the "handle"
 *
 * Return:
 *         The status code, TRANS_SUCCESS will be provided if OK.
 */
int trans_close(IN void *llc);

/*
 * Description:
 *         Get the local/remote endpoint of the attached handle.
 *
 * Note:
 *         Please read only.
 *
 * Parameters:
 *         llc        - Attached socket pointer as the "handle"
 *
 * Return:
 *         The endpoint address.
 */
const tsock_ep* trans_get_laddr(IN void *llc);
const tsock_ep* trans_get_raddr(IN void *llc);

/*
 * Description:
 *         trans_get_conn : Get the local/remote endpoint of the attached handle.
 *
 * Note:
 *         Please read only.
 *         And, currently, just return the first local addr and remote addr, for
 *         SCTP, need to do the enhancement.
 *
 * Parameters:
 *         llc        - Attached socket pointer as the "handle".
 *         l        - The pointer of the local endpoint passed in
 *         r        - The pointer of the remote endpoint passed in
 *
 * Return:
 *         TRANS_SUECCESS .
 */
int trans_get_conn(IN void *llc, OUT tsock_ep* l, OUT tsock_ep* r);

/*
 * Description:
 *         trans_get_my_ulc : Get the User-Level-Context once passed in
 *
 * Parameters:
 *         llc        - Attached socket pointer as the "handle"
 *
 * Return:
 *         User-Level-Context (void*)
 */
void* trans_get_my_ulc(IN void *llc);

/*
 * Description:
 *         trans_get_tid :  Get the thread ID about the "handle" attached
 *
 * Parameters:
 *         llc        - Attached socket pointer as the "handle"
 *
 * Return:
 *         thread id
 */
pthread_t trans_get_tid(IN void *llc);

/*
 * Description:
 *         trans_set_timer : The Timer setter.
 *
 * Parameters:
 *         ulc        - the User-Level-Context and it will be popup when timeout
 *         t_tlc     - the timer info user should save as the "handle"
 *         id        - timer id in the call back, suggest begin from 1
 *         m_sec    - mill sec
 *         cb        - the call back function
 *
 * Return:
 *         The status code, TRANS_SUCCESS will be provided if OK.
 */
int trans_set_timer(IN void *ulc, OUT void **tlc, IN int id,
    IN int m_sec, IN timer_cb cb);

/*
 * Description:
 *         trans_set_timer_ex : The Timer setter, extension version.
 *
 * Parameters:
 *         tlc        - the attached handle to t_tlc ever get or once used. if NULL
 *                     passing in, system will choose one source.
 *         ulc        - the user-level-context and it will be popup when timeout.
 *         t_llc     - the timer info user should save as the "handle".
 *         id        - timer id in the call back, suggest begin from 1.
 *         m_sec    - mill sec.
 *         cb        - the call back function.
 *         type    - could be a TIMER_TYPE_SIMPLE or TIMER_TYPE_REPEAT.
 *
 * Return:
 *         The status code, TRANS_SUCCESS will be provided if OK.
 */
int trans_set_timer_ex(IN void *tlc, IN void* ulc, OUT void **t_tlc,
    IN int id, IN int m_sec, IN timer_cb cb, IN int type);

/*
 * Description:
 *         trans_kill_timer : Kill the timer.
 *
 * Parameters:
 *         tlc     - the timer "handle" user saved.
 *         id        - timer id.
 *
 * Return:
 *         The status code, TRANS_SUCCESS will be provided if OK.
 */
int trans_kill_timer(IN void *tlc, IN int id);

/*
 * Description:
 *         trans_get_timer_remains : Get the remain ticks.
 *
 * Parameters:
 *         tlc     - the timer "handle" user saved.
 *
 * Return:
 *         > 0      The remain timer tick in mill second.
 *         = 0     Expired, or not exist now.
 *         < 0        The Error.
 */
int trans_get_timer_remains(IN void *tlc);

/*
 * Desctiption:
 *         A debug interface to print trans thread into and socket info
 *         to log.
 */
void trans_print(void);

#ifdef __cplusplus
}
#endif

#endif /* TRANS_H_ */
